package com.me.myFramework.aop22.aop122;

import com.me.myFramework.aop22.aop122.intercept.method.AfterReturningAdviceInterceptor122;
import com.me.myFramework.aop22.aop122.intercept.method.MethodBeforeAdviceInterceptor122;
import com.me.myFramework.aop22.aop122.intercept.method.ReflectiveMethodInvocation122;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;

/**
 * 《AOP-122》：  <br><br>
 * TODO 把 {@link MethodBeforeAdviceInterceptor122#invoke} 中的流程判断逻辑统一封装到 {@link ReflectiveMethodInvocation122#proceed()}，
 *          对于 MethodInterceptor、ProxyFactory#getProxy 来说，只需要调用 `MethodInvocation.proceed()` 即可
 */
public class ProxyFactory122 {

    private final Object target;
    private final List<Advice> advices = new ArrayList<>();

    public ProxyFactory122(Object target) {
        this.target = target;
    }

    public Object getProxy() {
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(), (proxy, method, args) -> {
            List<MethodInterceptor> interceptors = getInterceptors();
            if (interceptors.size() > 0) {
                Class<?> targetClass = target.getClass();
                MethodInvocation invocation = new ReflectiveMethodInvocation122(proxy, target, method, args, targetClass, interceptors);
                return invocation.proceed();
            }
            else {
                return method.invoke(target, args);
            }

        });
    }

    private List<MethodInterceptor> getInterceptors() {
        List<MethodInterceptor> interceptorList = new ArrayList<>(this.advices.size());
        for (Advice advice : this.advices) {
            if (advice instanceof MethodBeforeAdvice) {
                interceptorList.add(new MethodBeforeAdviceInterceptor122((MethodBeforeAdvice) advice));
            } else if (advice instanceof AfterReturningAdvice) {
                interceptorList.add(new AfterReturningAdviceInterceptor122((AfterReturningAdvice) advice));
            } else {
                // 实际是不存在这种情况的，因为 Advice 的子接口是自己定义的，也都会在这边判断
                throw new RuntimeException("GG, 未知的 Advice");
            }
        }

        return interceptorList;
    }

    public void addAdvice(Advice advice) {
        this.advices.add(advice);
    }

    private boolean isCustomMethod(String methodName) {
        return !("toString".equals(methodName) || "hashCode".equals(methodName) || "equals".equals(methodName)
                || "clone".equals(methodName));
    }

}
